package com.lyon.custom.server.common.notify;

import cn.hutool.core.util.ReflectUtil;

import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;

/**
 * @author LeeYan9
 * @since 2021-11-29
 */
public class NotifyCenter {

    private NotifyCenter() {
    }

    private static final NotifyCenter INSTANCE = new NotifyCenter();

    private final ConcurrentHashMap<String, Publisher> publisherMap = new ConcurrentHashMap<>();
    private static BiFunction<Class<? extends Publisher>, Class<? extends Event>, Publisher> publisherFactory;

    static {
        // 发布器工厂初始化
        publisherFactory = (publisherClass, eventClass) -> {
            // 创建实例， 设置消费对列长度 ， 默认1024
            Publisher publisher = ReflectUtil.newInstance(publisherClass);
            publisher.init(-1, eventClass);
            publisher.start();
            return publisher;
        };
    }


    public static boolean addSubscriber(Subscriber consumer, Class<? extends Event> subscriberType) {
        Objects.nonNull(subscriberType);
        String topic = subscriberType.getCanonicalName();
        Publisher publisher = publisherComputeIfAbsent(subscriberType, topic);
        publisher.addSubscriber(consumer);
        return true;
    }


    public static boolean publishEvent(Event event) {
        Publisher publisher = INSTANCE.publisherMap.get(getCanonicalName(event.getClass()));
        if (publisher == null) {
            return false;
        }
        publisher.publish(event);
        return true;
    }

    private static Publisher publisherComputeIfAbsent(Class<? extends Event> subscriberType, String topic) {
        Publisher publisher = INSTANCE.publisherMap.get(topic);
        if (publisher != null) {
            return publisher;
        }
        synchronized (NotifyCenter.class) {
            publisher = INSTANCE.publisherMap.get(topic);
            if (publisher != null) {
                return publisher;
            }
            publisher = publisherFactory.apply(DefaultPublisher.class, subscriberType);
            INSTANCE.publisherMap.put(topic,publisher);
            return publisher;
        }
    }


    private static String getCanonicalName(Class target) {
        Objects.nonNull(target);
        return target.getCanonicalName();
    }

}
